#!/bin/bash -e

#
# MSBuild wrapper to build Xamarin.Android apps from the command-line,
# without pesky IDE interference.
#
# Supported MSBuild targets and properties:
#   https://developer.xamarin.com/guides/android/under_the_hood/build_process/
#
# Overridable environment variables:
#   ANDROID_NDK_PATH:
#     Path to Android NDK.
#     Defaults to `$(AndroidNdkDirectory)` in ../../Configuration.props.
#   ANDROID_SDK_PATH:
#     Path to Android SDK.
#     Defaults to `$(AndroidNdkDirectory)` in ../../Configuration.props.
#   CONFIGURATION:
#     For in-source-tree invocations, the `bin/$(CONFIGURATION)` directory to
#     use as the installation prefix. If not specified, defaults to `Debug`.
#   MSBUILD:
#     MSBuild engine to use. Defaults to `xbuild`, assumed to be in `$PATH`
#   TARGETS_DIR:
#     The MSBuild `$(MSBuildExtensionsPath)` root location.
#     Defaults to `$prefix/lib/xamarin.android/xbuild`.
#
# Examples:
#   To create a .apk for the HelloWorld sample:
#     tools/scripts/xabuild /t:SignAndroidPackage samples/HelloWorld/HelloWorld/HelloWorld.csproj
#
#   To explicitly use `msbuild` for builds:
#     MSBUILD=msbuild tools/scripts/xabuild /t:SignAndroidPackage samples/HelloWorld/HelloWorld/HelloWorld.csproj
#
#   To explicitly use `xbuild` for builds:
#     MSBUILD=xbuild tools/scripts/xabuild /t:SignAndroidPackage samples/HelloWorld/HelloWorld/HelloWorld.csproj
#

name=$(basename "$0")
truepath=$(readlink "$0" || echo "$0")
prefix="$(cd `dirname "${truepath}"` && pwd)"

if [ -z "$MSBUILD" ] ; then
	MSBUILD=msbuild
fi

if [ -z "$CONFIGURATION" ]; then
	for p in "$@"; do
		case $p in
			/property:Configuration=*|                                                   \
			/p:Configuration=*|                                                          \
			-p:Configuration=*|                                                          \
			--property:Configuration=*) CONFIGURATION="`echo $p | cut -d '=' -f 2`" ;;
		esac

		if [ -n "$CONFIGURATION" ]; then
			break
		fi
	done
fi

if [[ "$prefix" == */tools/scripts ]] ; then
	Paths_targets="$prefix/../../build-tools/scripts/Paths.targets"
	for c in "$CONFIGURATION" Debug Release ; do
		if [ -z "$c" ]; then
			continue
		fi
		if [ -d "$prefix/../../bin/$c" ]; then
			real_prefix="$prefix/../../bin/$c"
			break
		fi
	done
	if [ -z "$real_prefix" ]; then
		(>&2 echo "$name: Could not determine Xamarin.Android prefix.")
		exit 1
	fi
	prefix="$real_prefix"
	xa_prefix="$real_prefix/lib/xamarin.android"
elif [[ "$prefix" == */bin ]] ; then
	prefix="$prefix/.."
	xa_prefix="$prefix/lib/xamarin.android"
else
	(>&2 echo "$name: Could not determine Xamarin.Android prefix.")
	exit 1
fi

if [[ "$MSBUILD" == "msbuild" ]] ; then
	exec mono "$prefix/bin/xabuild.exe" "$@" "/p:MonoDroidInstallDirectory=$prefix"
	exit $?
fi

for t in "$TARGETS_DIR" "$prefix/lib/mono/xbuild" "$xa_prefix/xbuild" ; do
	if [ -z "$t" -o ! -d "$t" ]; then
		continue
	fi
	TARGETS_DIR="$t"
	break
done

if [ ! -d "$TARGETS_DIR" ]; then
	(>&2 echo "$name: Could not determine Xamarin.Android targets path.")
	exit 1
fi
export TARGETS_DIR
export MONO_ANDROID_PATH="$prefix"

if [ -f "$Paths_targets" ] ; then
	ANDROID_NDK_PATH=$($MSBUILD /nologo /v:minimal /t:GetAndroidNdkFullPath "$Paths_targets")
	ANDROID_NDK_PATH=$(echo $ANDROID_NDK_PATH | sed 's/^\w*//g')
	export ANDROID_NDK_PATH

	ANDROID_SDK_PATH=$($MSBUILD /nologo /v:minimal /t:GetAndroidSdkFullPath "$Paths_targets")
	ANDROID_SDK_PATH=$(echo $ANDROID_SDK_PATH | sed 's/^\w*//g')
	export ANDROID_SDK_PATH
fi

declare -a XABUILD_FLAGS

XABUILD_FLAGS=(
	/p:MonoAndroidToolsDirectory="$xa_prefix/xbuild/Xamarin/Android"
	/p:MonoDroidInstallDirectory="$MONO_ANDROID_PATH"
)

if [ -n "$ANDROID_NDK_PATH" ] ; then
	XABUILD_FLAGS+=(/p:AndroidNdkDirectory="$ANDROID_NDK_PATH")
fi
if [ -n "$ANDROID_SDK_PATH" ] ; then
	XABUILD_FLAGS+=(/p:AndroidSdkDirectory="$ANDROID_SDK_PATH")
fi

export MSBuildExtensionsPath="$TARGETS_DIR"

case "$MSBUILD" in
	*msbuild*)
		XABUILD_FLAGS+=(/p:TargetFrameworkRootPath="$TARGETS_DIR-frameworks/")
		;;
	*xbuild*)
		if [ -z "$XBUILD_FRAMEWORK_FOLDERS_PATH" ]; then
			export XBUILD_FRAMEWORK_FOLDERS_PATH="$TARGETS_DIR-frameworks"
		else
			export XBUILD_FRAMEWORK_FOLDERS_PATH="$XBUILD_FRAMEWORK_FOLDERS_PATH"
		fi
		;;
esac

function GetXbuildDir()
{
	read -r -d '' get_xbuild_dir_cmd <<-'EOF' || true
		using System.IO;
		var corlib_loc = typeof (int).Assembly.Location;
		// e.g. corlib_dir=/Library/Frameworks/Mono.framework/Versions/5.2.0/lib/mono/4.5
		var corlib_dir = Path.GetDirectoryName (corlib_loc);
		// e.g. xbuild_dir=/Library/Frameworks/Mono.framework/Versions/5.2.0/lib/mono/xbuild
		var xbuild_dir = Path.Combine (corlib_dir, "..", "xbuild");
		print (Path.GetFullPath (xbuild_dir));
	EOF
	echo "$get_xbuild_dir_cmd" | csharp
}

function ConfigureLocalXbuild()
{
	if [ -d "$prefix/lib/mono" ]; then
		# System installation, e.g. Linux?
		return 0
	fi
	xbuild_dir=`GetXbuildDir`
	local sys_entry=`ls -1 "$xbuild_dir" | head -1`
	if [ -f "$TARGETS_DIR/.__sys_links.txt" ] ; then
		# already configured; bail
		return 0
	fi
	local sys_links="$TARGETS_DIR/.__sys_links.txt"
	echo ".__sys_links.txt" > "$sys_links"
	local e
	for e in "$xbuild_dir"/* ; do
		local b=`basename "$e"`
		if [ -e "$TARGETS_DIR/$b" -o -f "$TARGETS_DIR/$b" -o -L "$TARGETS_DIR/$b" ]; then
			rm -rf "$TARGETS_DIR/$b"
		fi
		ln -s "$e" "$TARGETS_DIR"
		if [ -d "$e" ]; then
			echo "$b"'/*' >> "$sys_links"
		else
			echo $b >> "$sys_links"
		fi
	done
}

ConfigureLocalXbuild

exec $MSBUILD "${XABUILD_FLAGS[@]}" "$@"
